﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BonsaiScrum.Core.Domain.Shared;

namespace BonsaiScrum.Core.Domain
{
    public class User : BaseEntity<User>
    {
        private string _userName;
        private PermissionLevel _maximumAuthorizedPermissionLevel;
        private string _firstname;
        private string _lastname;
        private string _password;
        private IList<Task> _tasks;

        protected User() 
        {
            _maximumAuthorizedPermissionLevel = PermissionLevel.Developer;
            _tasks = new List<Task>();
        }

        public User(string userName, string password, string firstname, string lastname, PermissionLevel permissionLevel) : this()
        {
            if (string.IsNullOrEmpty(userName))
                throw new ArgumentNullException("userName");

            _userName = userName;
            _password = password;
            _firstname = firstname;
            _lastname = lastname;
            _maximumAuthorizedPermissionLevel = permissionLevel ?? PermissionLevel.Developer;
        }

        public virtual TRole GetRole<TRole>() where TRole : class, IRole, new()
        {
            var role = new TRole();

            if (IsAuthorizedForPermissionLevel(role.PermissionLevel))
            {
                CheckToMakeSureRoleHasProperConstructor<TRole>();

                return (TRole)Activator.CreateInstance(typeof(TRole), this);
            }
            
            throw new AuthorizationException(UserName, typeof(TRole));
        }

        private void CheckToMakeSureRoleHasProperConstructor<TRole>() where TRole : class, IRole, new()
        {
            var roleType = typeof(TRole);

            var roleConstructor = roleType.GetConstructor(new Type[] { typeof(User) });

            if (roleConstructor == null)
                throw new NotSupportedException("Role class must contain a public constructor with one parameter for the User.");

        }

        private bool IsAuthorizedForPermissionLevel(PermissionLevel permissionLevel)
        {
            return _maximumAuthorizedPermissionLevel.IsAuthorizedFor(permissionLevel);
        }

        protected internal virtual void Disable()
        {
            _maximumAuthorizedPermissionLevel = PermissionLevel.Disabled;
        }

        public virtual bool IsManager()
        {
            return _maximumAuthorizedPermissionLevel.Equals(PermissionLevel.Manager);
        }

        public virtual string UserName { get { return _userName; } }

        public override string ToString()
        {
            return string.Format("{0}: ({1})", _userName, _maximumAuthorizedPermissionLevel.Name);
        }

        public virtual void AddTask(Task task)
        {
            if (task == null)
                throw new ArgumentNullException("task");

            CheckToMakeSureUserIsNotDisabled();
            _tasks.Add(task);
        }

        private void CheckToMakeSureUserIsNotDisabled()
        {
            if (_maximumAuthorizedPermissionLevel.Equals(PermissionLevel.Disabled))
                throw new UserDisabledException(_userName);
        }
    }
}
